//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <car.h>
#include "marshal.h"
#include "prxstub.h"
#include "rot.h"
#include "stdlib.h"
#include "_sprintf.h"
#include <aura.h>
#include <sharecls.h>
#include <classinfo.h>
#include <pcentral.h>

#if defined(_DEBUG)

static ECode SetThreadName(Address uMethodAddr)
{
    return NOERROR;
}

#endif // _DEBUG

ECode CInterfaceStub::UnmarshalIn(
    /* [in] */ const CIMethodEntry *pMethodInfo,
    /* [in] */ MarshalHeader *pInHeader,
    /* [in, out] */ MarshalHeader *pOutHeader,
    /* [in, out] */ UInt32 *puArgs)
{
    // TODO: should modify it
    ECode ec;

    assert(pInHeader->m_pContext == CTX_KERN_2_USER
        || pInHeader->m_pContext == CTX_DIFF_PROCESS
        || pInHeader->m_pContext == CTX_DIFF_MACHINE);

    ec = Stub_ProcessUnmsh_In(
        pMethodInfo,
        (UInt32 *)(pInHeader + 1),
        pInHeader->m_uInSize - sizeof(MarshalHeader),
        (UInt32 *)pOutHeader,
        pInHeader->m_uOutSize,
        puArgs);

    if (pOutHeader && SUCCEEDED(ec)) {
        memcpy(pOutHeader, pInHeader, sizeof(MarshalHeader));
    }
    return ec;
}

ECode CInterfaceStub::MarshalOut(
    /* [in] */ UInt32 *puArgs,
    /* [in] */ MarshalHeader *pInHeader,
    /* [out] */ MarshalHeader *pOutHeader,
    /* [in] */ bool_t bOnlyReleaseIn)
{

    assert(!pOutHeader
        || pOutHeader->m_pContext == CTX_KERN_2_USER
        || pOutHeader->m_pContext == CTX_DIFF_PROCESS
        || pOutHeader->m_pContext == CTX_DIFF_MACHINE);

    return Stub_ProcessMsh_Out(
        &(m_pInfo->methods[pInHeader->m_hMethodIndex - 3]),
        puArgs,
        (UInt32 *)pOutHeader,
        bOnlyReleaseIn);
}

PInterface CObjectStub::Probe(REIID riid)
{
    int n;

    if (riid == EIID_IInterface) {
        return (IInterface *)this;
    }

    for (n = 0; n < m_cInterfaces; n++) {
        if (riid == m_pInterfaces[n].m_pInfo->iid) {
            break;
        }
    }
    if (n == m_cInterfaces) {
        MARSHAL_DBGOUT(MSHDBG_WARNING, printf(
            "Stub(%d): QI failed, iid: ", m_oid));
        MARSHAL_DBGOUT(MSHDBG_WARNING, DUMP_GUID(riid));

        return NULL;
    }

    return m_pInterfaces[n].m_pObject;
}

UInt32 CObjectStub::AddRef(void)
{
    Int32 lRefs = m_cRefs.Increment();

    MARSHAL_DBGOUT(MSHDBG_CREF, printf(
        "Stub(%d) AddRef: %d\n", m_oid, lRefs));
    return (UInt32)lRefs;
}

extern PVoid g_marshalLock;

UInt32 CObjectStub::Release(void)
{
    ECode ec;

    AuraCriticalSection_Enter(g_marshalLock);
    Int32 lRefs = m_cRefs.Decrement();

    if (lRefs == 0) {
        MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
            "Stub destructed, oid(%d)\n", m_oid));

        ec = UnregisterExportObject(m_oid);
        AuraCriticalSection_Leave(g_marshalLock);
        if (S_FALSE == ec) return 1;// other thread hold the Stub
        delete this;

        return 0;
    }
    else {
        AuraCriticalSection_Leave(g_marshalLock);
    }

    MARSHAL_DBGOUT(MSHDBG_CREF, printf(
        "Stub(%d) Release: %d\n", m_oid, lRefs));
    return (UInt32)lRefs;
}

ECode CObjectStub::Aggregate(
    /* [in] */ AggregateType type,
    /* [in] */ PInterface pObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CObjectStub::GetDomain(
    /* [out] */ IInterface **ppObj)
{
    return E_NOT_IMPLEMENTED;
}

EXTERN_C ECode Reply(
        UInt32 channelID, void *pvOutBuf, size_t uOutBufSize, _ELASTOS Boolean bCleanupTLSlots);

#ifdef _arm
void CObjectStub::Invoke(
    /* [in] */ UInt32 uClientId,
    /* [in] */ void *pvData,
    /* [in] */ UInt32 uSize)
{
    this->_Invoke(uClientId, pvData, uSize);
}

#ifdef _MSVC
EXTERN_C void StubInvokeMethod1(
        ECode *pHR, UInt32 *puArgs, UInt32 uMethodAddr, UInt32 regs[8]);

EXTERN_C void StubInvokeMethod2(
        ECode *pHR, UInt32 *puArgs, UInt32 uMethodAddr, UInt32 regs[8]);
#endif
//_MSVC
#endif //_arm

#ifdef _x86
void CObjectStub::Invoke(
    /* [in] */ UInt32 uClientId,
    /* [in] */ void *pvData,
    /* [in] */ UInt32 uSize)
#elif defined(_arm)
void CObjectStub::_Invoke(
    /* [in] */ UInt32 uClientId,
    /* [in] */ void *pvData,
    /* [in] */ UInt32 uSize)
#elif defined(_mips)
void CObjectStub::Invoke(
    /* [in] */ void *pvData,
    /* [in] */ UInt32 uSize)
#else
#error unknown architecture
#endif
{
    assert(pvData != NULL);
    MarshalHeader *pInHeader, *pOutHeader = NULL;
    PVoid pOutBuf = NULL;
    UInt32 *puArgs, uMethodAddr, uMethodIndex;
    ECode ec, orgec = NOERROR;
    CInterfaceStub *pCurInterface;
    const CIMethodEntry *pMethodInfo;
    UInt32 uOutSize;
#ifdef _x86
    UInt32 uEAX, uEDX, uECX, uESP;
#elif defined(_arm)
    struct ArgumentBuffer
    {
        UInt32    r0;
        UInt32    r1;
        UInt32    r2;
        UInt32    r3;
    } argbuf;
#if defined(_GNUC)
    UInt32 r0, r1, r2, r3, ip, lr, sp;
#elif defined(_MSVC)
    UInt32 regs[8];
#else
#error Unknown C++ compiler
#endif
// defined(_GNUC)
#elif defined(_mips)
    UInt32 uV0, uV1;
    UInt32 uA0, uA1, uA2, uA3;
    UInt32 uT0, uT1, uT2, uT3, uT4, uT5, uT6, uT7, uT8, uT9;
    UInt32 uSp;
#else
#error unknown architecture
#endif
    bool_t bOnlyReleaseIn = FALSE;
    Boolean bCleanupTLSlots = FALSE;

    MARSHAL_DBGOUT(MSHDBG_NORMAL,
        printf("Stub(%d): in Invoke: isize(%d)\n", m_oid, uSize));

    pInHeader = (MarshalHeader *)pvData;
    if (pInHeader->m_uMagic != MARSHAL_MAGIC) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("Stub: invalid magic - %x\n", pInHeader->m_uMagic));
        goto ErrorExit;
    }

#if defined(_DEBUG)
    if (uSize < sizeof(MarshalHeader)) {
        goto ErrorExit;
    }
    if (uSize != pInHeader->m_uInSize) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("Stub: in size error - %d:%d\n",
                uSize, pInHeader->m_uInSize + sizeof(MarshalHeader) - 1));
        goto ErrorExit;
    }
    if (pInHeader->m_oid != m_oid) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("Stub: oid error - %d:%d\n", pInHeader->m_oid, m_oid));
        goto ErrorExit;
    }
    if (pInHeader->m_hInterfaceIndex >= m_cInterfaces) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("Stub: interface index error - %d:%d\n",
                pInHeader->m_hInterfaceIndex, m_cInterfaces));
        goto ErrorExit;
    }
    MARSHAL_DBGOUT(MSHDBG_NORMAL,
        printf("Stub: interface idx(%d), method idx(%d)\n",
            pInHeader->m_hInterfaceIndex, pInHeader->m_hMethodIndex));
#endif

    if (pInHeader->m_hMethodIndex >= 3) {
        pCurInterface = &(m_pInterfaces[pInHeader->m_hInterfaceIndex]);

        uMethodIndex = pInHeader->m_hMethodIndex - 3;
        if (uMethodIndex >= pCurInterface->m_pInfo->methodNumMinus3) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Stub: method index out of range - %d:%d\n",
                    uMethodIndex,
                    pCurInterface->m_pInfo->methodNumMinus3));
            goto ErrorExit;
        }

        uMethodAddr =
                pCurInterface->m_pInterface->m_vPtr->m_vTable[uMethodIndex + 3];

#if defined(_DEBUG)
        // Set the name of the current thread: L"module+offset"
        //
        ec = SetThreadName(uMethodAddr);
        if (FAILED(ec)) {
            MARSHAL_DBGOUT(MSHDBG_NORMAL,
                printf("Stub: set thread name failed, ec = 0x%08x\n", ec));
            goto ErrorExit;
        }
#endif // _DEBUG

        pOutBuf = (PVoid)_alloca(pInHeader->m_uOutSize + 8);
        if (!pOutBuf) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Stub error: alloca() failed.\n"));
            ec = E_OUT_OF_MEMORY;
            goto ErrorExit;
        }

        if (0 != pInHeader->m_uOutSize) {
            SET_REPLY_TYPE(pOutBuf, Reply_ECodeAndOutput);
            // we will add the Ecode(returned value) after method call.
            pOutHeader = (MarshalHeader*)BY_REFERENCE(pOutBuf, 2);
        }
        else {
            SET_REPLY_TYPE(pOutBuf, Reply_ECodeOnly);
        }

        pMethodInfo = &((pCurInterface->m_pInfo)->methods[uMethodIndex]);
        uSize = GET_LENGTH(pMethodInfo->reserved1) * 4 + 4;
        MARSHAL_DBGOUT(MSHDBG_NORMAL,
            printf("Stub: method args stack size (%d)\n", uSize));
        puArgs = (UInt32 *)_alloca(uSize);
        if (!puArgs) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Stub error: alloca() failed.\n"));
            ec = E_OUT_OF_MEMORY;
            goto ErrorExit;
        }
#ifdef _x86
        GET_REG(ESP, puArgs);
#endif

        ec = pCurInterface->UnmarshalIn(pMethodInfo,
                                        pInHeader,
                                        pOutHeader,
                                        puArgs + 1);
        if (FAILED(ec)) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Stub error: UnmarshalIn() failed.\n"));
            goto ErrorExit;
        }

        *puArgs = (UInt32)pCurInterface->m_pObject; // fill this

        MARSHAL_DBGOUT(MSHDBG_NORMAL,
            printf("Stub: invoke method - args(%x), addr(%x) \n",
                puArgs, uMethodAddr));

#ifdef _x86
        GET_REG(EAX, uEAX);
        GET_REG(EDX, uEDX);
        GET_REG(ECX, uECX);
        GET_REG(ESP, uESP);
        assert(uESP == (UInt32)puArgs);
        // NOTE: we should promise STUB_INVOKE_METHOD just occures
        // in use space , if it used in kernel mode , the return
        // args in stack have the possibilty for being modified
        //
        STUB_INVOKE_METHOD(ec, puArgs, uMethodAddr);
        SET_REG(ECX, uECX);
        SET_REG(EDX, uEDX);
        SET_REG(EAX, uEAX);
#elif defined(_arm)

#if defined(_GNUC)
        if (sizeof(uint32_t) * 4 >= uSize) {
            GET_REG(r0, r0);
            GET_REG(r1, r1);
            GET_REG(r2, r2);
            GET_REG(r3, r3);
            GET_REG(ip, ip);
            GET_REG(lr, lr);
            STUB_INVOKE_METHOD1(ec, puArgs, uMethodAddr);
            SET_REG(lr, lr);
            SET_REG(ip, ip);
            SET_REG(r3, r3);
            SET_REG(r2, r2);
            SET_REG(r1, r1);
            SET_REG(r0, r0);
        }
        else {
            argbuf = *(ArgumentBuffer *)puArgs;
            GET_REG(r0, r0);
            GET_REG(r1, r1);
            GET_REG(r2, r2);
            GET_REG(r3, r3);
            GET_REG(ip, ip);
            GET_REG(lr, lr);
            GET_REG(sp, sp);
            STUB_INVOKE_METHOD2(ec, puArgs, uMethodAddr);
            SET_REG(sp, sp);
            SET_REG(lr, lr);
            SET_REG(ip, ip);
            SET_REG(r3, r3);
            SET_REG(r2, r2);
            SET_REG(r1, r1);
            SET_REG(r0, r0);
            *(ArgumentBuffer *)puArgs = argbuf;
        }
#elif defined(_MSVC)
        if (sizeof(uint32_t) * 4 >= uSize) {
            StubInvokeMethod1(&ec, puArgs, uMethodAddr, regs);
        }
        else {
            argbuf = *(ArgumentBuffer *)puArgs;
            StubInvokeMethod2(&ec, puArgs, uMethodAddr, regs);
            *(ArgumentBuffer *)puArgs = argbuf;
        }
#else

#error Unknown C++ compiler

#endif
// defined(_GNUC)
#elif defined(_mips)
        GET_REG($2, uV0);
        GET_REG($3, uV1);
        GET_REG($4, uA0);
        GET_REG($5, uA1);
        GET_REG($6, uA2);
        GET_REG($7, uA3);
        GET_REG($8, uT0);
        GET_REG($9, uT1);
        GET_REG($10, uT2);
        GET_REG($11, uT3);
        GET_REG($12, uT4);
        GET_REG($13, uT5);
        GET_REG($14, uT6);
        GET_REG($15, uT7);
        GET_REG($24, uT8);
        GET_REG($25, uT9);
        GET_REG($29, uSp);
        STUB_INVOKE_METHOD(ec, puArgs, uMethodAddr);
        SET_REG($29, uSp);
        SET_REG($2, uV0);
        SET_REG($3, uV1);
        SET_REG($4, uA0);
        SET_REG($5, uA1);
        SET_REG($6, uA2);
        SET_REG($7, uA3);
        SET_REG($8, uT0);
        SET_REG($9, uT1);
        SET_REG($10, uT2);
        SET_REG($11, uT3);
        SET_REG($12, uT4);
        SET_REG($13, uT5);
        SET_REG($14, uT6);
        SET_REG($15, uT7);
        SET_REG($24, uT8);
        SET_REG($25, uT9);
#else
#error unknown architecture
#endif

        bCleanupTLSlots = TRUE;

        if (FAILED(ec) && GET_IN_INTERFACE_MARK(pMethodInfo->reserved1)) {
            bOnlyReleaseIn = TRUE;
        }

        bool_t bErrorInfo = IsUserECode(ec);

        // puArgs + 1 , skip this pointer
        if ((pOutHeader && (SUCCEEDED(ec) || bErrorInfo))
            || GET_IN_INTERFACE_MARK(pMethodInfo->reserved1)) {

            orgec = pCurInterface->MarshalOut(puArgs + 1, pInHeader, \
                                          pOutHeader, bOnlyReleaseIn);
            if (FAILED(orgec)) {
                MARSHAL_DBGOUT(MSHDBG_ERROR, printf(
                    "Stub: marshal out args fail, hr(%x)\n", ec));
                ec = orgec;
                goto ErrorExit;
            }

            if (bErrorInfo) {
                StubMarshalOutErrorInfo(pOutHeader);

                assert(pOutHeader->m_pContext == CTX_DIFF_PROCESS ||
                           pOutHeader->m_pContext == CTX_DIFF_MACHINE);
                assert(((MarshalHeader *)pInHeader)->m_uOutSize >=
                            pOutHeader->m_uOutSize);
            }
        }
    }
    else if (pInHeader->m_hMethodIndex == 0) {
        MARSHAL_DBGOUT(MSHDBG_ERROR,
            printf("Stub error: Remote Probe(), oid = 0x%08x\n",
            pInHeader->m_oid));
        ec = E_INVALID_OPERATION;    // Do not allow remote Probe().
        goto ErrorExit;
    }
    else if (pInHeader->m_hMethodIndex == 1) {
        // use "ec" to transport the reference
        ec = this->AddRef();

        MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
            "Stub: remote AddRef(), cRefs(%d)\n", ec));
        goto Exit;
    }
    else {
        // use "ec" to transport the reference
        ec = this->Release();

        MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
            "Stub: remote Release(), cRefs(%d)\n", ec));
        goto Exit;
    }

    MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
        "Stub(%d): invoke server method ok, _SysReply osize(%d)\n",
        pInHeader->m_oid, pInHeader->m_uOutSize));

    // Pass the actual uOutSize to SysReply
    //
    uOutSize = pInHeader->m_uOutSize;
    if (pOutHeader) {
        assert(pInHeader->m_uOutSize >= pOutHeader->m_uOutSize);
        uOutSize = pOutHeader->m_uOutSize;
    }

    SET_REPLY_ECODE(pOutBuf, ec);
    Reply(uClientId, pOutBuf, REPLY_BUF_SIZE(uOutSize), bCleanupTLSlots);
    return ;

Exit:
ErrorExit:
    UInt32 uData[2];

    SET_REPLY_TYPE(uData, Reply_ECodeOnly);
    SET_REPLY_ECODE(uData, ec);

    Reply(uClientId, uData, REPLY_BUF_SIZE(0), bCleanupTLSlots);

    return;
}

ECode CObjectStub::GetOid(
    /* [out] */ oid_t *pOid)
{
    *pOid = m_oid;
    return NOERROR;
}

ECode CObjectStub::GetClsid(
    /* [out] */ EMuid *pClsid)
{
    *pClsid = ((CIClassEntry*)m_pInfo)->clsid;
    return NOERROR;
}

ECode CObjectStub::GetClassEntry(
    /* [out] */ UInt32 *pClassEntry)
{
    *pClassEntry = m_pInfo;
    return NOERROR;
}

ECode CObjectStub::InterfaceIndex(
    /* [in] */ IInterface *pObj,
    /* [out] */ UInt32 *puIndex)
{
    for (UInt32 n = 0; n < (UInt32)m_cInterfaces; n++) {
        if (m_pInterfaces[n].m_pObject == pObj) {
            *puIndex = n;
            return NOERROR;
        }
    }
    MARSHAL_DBGOUT(MSHDBG_WARNING, printf(
        "Stub(%d): InterfaceIndex failed - pObj(%x)\n", m_oid, pObj));

    return E_NO_INTERFACE;
}

ECode CObjectStub::S_CreateObject(
    /* [in] */ IInterface *pObject,
    /* [out] */ IStub **ppIStub)
{
    return S_CreateObject(NULL, pObject, ppIStub);
}

ECode CObjectStub::S_CreateObject(
    /* [in] */ const wchar_t *pwszName,
    /* [in] */ IInterface *pObject,
    /* [out] */ IStub **ppIStub)
{
    CObjectStub *pStub;
    CInterfaceStub *pInterfaces;
    IInterface *pObj;
    EMuid *pClsid;
    EIID * pIID;
    ECode ec = NOERROR;
    CIClassEntry ** ppClassInfo = NULL;
    int n;
    int uIndex = 0;

    if (!pObject || !ppIStub) {
        return E_INVALID_ARGUMENT;
    }

    *ppIStub = NULL;

    pStub = new CObjectStub;
    if (!pStub) {
        return E_OUT_OF_MEMORY;
    }
    pStub->AddRef();

    pClsid = (EMuid *)pObject->Probe(EIID_CLASS_INFO);
    if (!pClsid) {
        MARSHAL_DBGOUT(MSHDBG_ERROR, printf(
            "Create stub: interface do not support EIID_CLASS_INFO QI.\n"));
        goto ErrorExit;
    }
    MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
        "QI class info ok. EMuid is:\n"));
    MARSHAL_DBGOUT(MSHDBG_NORMAL, DUMP_CLSID((RClassID)*pClsid));

    pIID = (EIID *)pObject->Probe(EIID_INTERFACE_INFO);
    if (!pIID) {
        MARSHAL_DBGOUT(MSHDBG_ERROR, printf(
            "Create stub: interface do not support EIID_INTERFACE_INFO QI.\n"));
        goto ErrorExit;
    }
    MARSHAL_DBGOUT(MSHDBG_NORMAL, printf(
        "QI EIID info ok. EIID is:\n"));
    MARSHAL_DBGOUT(MSHDBG_NORMAL, DUMP_GUID(*pIID));

    bool_t bIsSystemInterface;

    //
    // find the clsinfo in local table , if the interface is a system interface
    //
    ec = LookupServerClassEntry(*pClsid, \
                     (const CIClassEntry **)&(pStub->m_pInfo));
    if (FAILED(ec)) {
        MARSHAL_DBGOUT(MSHDBG_NORMAL,
            printf("Create stub: class info not in local ClassInfo Table.\n"));

        ec = LookupSharedClassEntry(*pClsid, (CIClassEntry **)&(pStub->m_pInfo));

        if (FAILED(ec)) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Create Stub: get class info fail, the ec = 0x%08x\n", ec));
            goto ErrorExit;
        }

        bIsSystemInterface = FALSE;
    }
    else {
        bIsSystemInterface = TRUE;
    }

    ppClassInfo = (CIClassEntry **)&(pStub->m_pInfo);

    MARSHAL_DBGOUT(MSHDBG_NORMAL,
        printf("Create stub: _SysRegister ok. oid = %d\n", pStub->m_oid));

    pInterfaces = new CInterfaceStub[(*ppClassInfo)->interfaceNum];
    if (!pInterfaces) {
        MARSHAL_DBGOUT(MSHDBG_ERROR, printf("Create stub: out of memory.\n"));
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    pStub->m_cInterfaces = (*ppClassInfo)->interfaceNum;
    pStub->m_pInterfaces = pInterfaces;
    pObject->AddRef();
    for (n = 0; n < (*ppClassInfo)->interfaceNum; n++) {
        CIInterfaceEntry *pInterfaceInfo =
            (CIInterfaceEntry *)GetUnalignedPtr(
                (*ppClassInfo)->interfaces + n);
        pObj = pObject->Probe(pInterfaceInfo->iid);
        if (!pObj) {
            MARSHAL_DBGOUT(MSHDBG_ERROR,
                printf("Create stub: no such interface.\n"));
            ec = E_NO_INTERFACE;
            pObject->Release();
            goto ErrorExit;
        }
        pInterfaces[n].m_pInfo = pInterfaceInfo;
        pInterfaces[n].m_pObject = pObj;
        if (pInterfaceInfo->iid == *pIID) {
            uIndex = n;
        }
    }

    if (bIsSystemInterface) ppClassInfo = NULL;

    if (!pwszName) {
        ec = CPseudoCentral::SrvcRegister(pClsid, pIID, uIndex, &pStub->m_oid);
    }
    else {
        ec = CPseudoCentral::SrvcRegisterCommon(pwszName, pClsid, pIID, uIndex, &pStub->m_oid);
    }

    if (FAILED(ec)) {
        pObject->Release();
        MARSHAL_DBGOUT(MSHDBG_ERROR, printf("Stub: register server failed (ec = 0x%x).(name=%S)\n",
            ec, pwszName));
        goto ErrorExit;
    }

    ec = RegisterExportObject(pStub->m_oid, pObject, pStub);
    if (FAILED(ec)) {
        pObject->Release();
        MARSHAL_DBGOUT(MSHDBG_ERROR, printf(
            "Create stub: register export object failed, ec(%x)\n", ec));
        goto ErrorExit;
    }

    *ppIStub = (IStub *)pStub;

    return NOERROR;

ErrorExit:

    delete pStub;
    return ec;
}

CObjectStub::~CObjectStub()
{
    if (m_pInterfaces) {
        if (m_oid != 0) {
            m_pInterfaces[0].m_pObject->Release();
            CPseudoCentral::SrvcUnregister(m_oid);
        }
        delete [] m_pInterfaces;
    }
}
